#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/12/10 10:43
# @Author  : XH
# @File    : Http_token
# @Software: PyCharm
import base64
import json
from dataclasses import dataclass, field
from typing import Dict, Optional, Any
from urllib.parse import urlencode
import requests
from common.handle_log import mylog
from common.handle_yaml import HandleYaml


@dataclass
class Request:
    """
    封装发送请求所需的字段和方法，方便后续扩展和维护。

    Attributes:
        method (str): 请求方法，默认为 None，可以是 "GET", "POST", 等等。
        headers (dict): 请求头部，默认为空字典。
        host (str): 主机地址。
        path (str): 请求路径。
        data (dict, optional): 请求体数据，默认为 None。
        query (dict, optional): 查询参数，默认为 None。
        type (str): 请求体格式，默认为 "json"。可以是 "json", "xml", "text", "form"。
        proxies (dict, optional): 请求代理，默认为 None。
        allow_redirects (bool): 是否允许重定向，默认为 True。
        verify (bool): 是否验证 SSL 证书，默认为 False。
        timeout (int): 请求超时时间，默认为 30 秒。
    """

    method: str = None
    headers: Dict[str, str] = field(default_factory=dict)
    host: str = None
    path: str = None
    data: Optional[Dict[str, Any]] = None
    query: Optional[Dict[str, Any]] = None
    type: str = "json"
    proxies: Optional[Dict[str, str]] = None
    allow_redirects: bool = True
    verify: bool = False
    timeout: int = 30  # 设置默认超时时间为 30 秒


    def prepare_data(self):
        """根据请求类型设置 Content-Type 和处理数据"""
        if self.type == "json":
            self.headers["Content-Type"] = "application/json"
            if self.data:
                self.data = json.dumps(self.data)
        elif self.type == "xml":
            self.headers["Content-Type"] = "application/xml"
        elif self.type == "text":
            self.headers["Content-Type"] = "text/plain"
            if self.data:
                self.data = str(self.data)  # 将数据转换为字符串
        elif self.type == "form":
            self.headers["Content-Type"] = "application/x-www-form-urlencoded"
            if self.data:
                self.data = urlencode(self.data)
        else:
            raise ValueError(f"Unsupported request type: {self.type}")

    def debug_log_request_details(self, url: str):
        """记录请求的详细信息"""
        mylog.debug(f"Request URL: {url}")
        mylog.debug(f"Request Headers: {self.headers}")
        if self.data:
            mylog.debug(f"Request Data: {self.data}")
        if self.query:
            mylog.debug(f"Request Query Params: {self.query}")

    def send(self) -> 'Response':
        """
        发送请求并返回 Response 对象。
        处理请求的构造与发送，并捕获可能的异常。
        """
        # 从 YAML 配置文件中加载主机地址
        if self.host is None:
            yaml_file = 'env_config.yaml'  # 你的YAML文件路径
            self.host = HandleYaml(yaml_file).get_value("env")["test"]  # 加载环境配置中的 host
        # 构造完整的 URL
        url = f"{self.host}{self.path}"

        # 设置请求头和请求体数据
        self.prepare_data()

        # 记录请求详情
        self.debug_log_request_details(url)

        try:
            # 发送请求
            requests_response = requests.request(
                method=self.method,
                url=url,
                headers=self.headers,
                data=self.data,
                params=self.query,
                timeout=self.timeout,
                proxies=self.proxies,
                allow_redirects=self.allow_redirects,
                verify=self.verify
            )

            # 记录响应信息
            mylog.debug(f"Response Status Code: {requests_response.status_code}")
            # mylog.debug(f"Response Headers: {requests_response.headers}")
            mylog.debug(f"Response Body: {requests_response.json()}")

            # 返回封装的响应对象
            return Response(requests_response)

        except requests.Timeout:
            mylog.error("Request timed out")
            raise TimeoutError(f"The request timed out after {self.timeout} seconds")
        except requests.RequestException as e:
            mylog.error(f"Request failed: {e}")
            raise SystemExit(f"Request failed: {e}")

@dataclass
class Response:
    """
    封装 requests 库响应对象，提供对响应内容的访问方法。

    Attributes:
        r (requests.Response): 原始的 requests 响应对象。
    """
    r: requests.Response

    def json(self):
        """
        尝试解析响应体为 JSON 格式并返回。
        如果解析失败，则返回 None。
        """
        try:
            return self.r.json()
        except ValueError as e:
            mylog.error(f"Error parsing JSON: {e}")
            return None

    @property
    def status_code(self):
        """
        返回响应的 HTTP 状态码。
        """
        return self.r.status_code

    def data(self) -> dict:
        """
        解析并返回响应体的数据，假设响应体是经过 base64 编码的。
        """
        try:
            return json.loads(base64.b64decode(self.r.text))
        except (base64.binascii.Error, json.JSONDecodeError) as e:
            mylog.error(f"Error decoding or parsing response data: {e}")
            return {}


if __name__ == '__main__':
    # 创建get示例
    # request = Request(
    #     method="GET",
    #     host="https://jsonplaceholder.typicode.com",
    #     path="/posts",
    #     query = {"userId": 1},
    # )
    # response = request.send()
    # print(response.status_code)
    # print(response.json())
    # # 创建post示例
    post_req = Request(
        method="POST",
        host="https://jsonplaceholder.typicode.com",
        path="/posts",
        data={"title": "foo", "body": "bar", "userId": 1},
        headers={"Authorization": "Bearer some_token"},
        type="json",
        timeout=5  # 设置 5 秒超时
    )
    res = post_req.send()
    print(res.status_code)
    print(res.json())